package com.katze.tools.hadoop.controller;

import com.katze.common.Code;
import com.katze.common.CommonUtils;
import com.katze.common.DatePattern;
import com.katze.common.Message;
import com.katze.common.controller.BaseController;
import com.katze.common.env.AppEnvironment;
import com.katze.common.zip.ZipCompressHolder;
import com.katze.tools.hadoop.config.HadoopManager;
import com.katze.tools.hadoop.config.HdfsFileType;
import com.katze.tools.hadoop.entity.HadoopDTO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;

@RestController
@RequestMapping("/hadoop")
@ConditionalOnBean(HadoopManager.class)
public class HadoopController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(HadoopController.class);

    @Autowired
    private HadoopManager manager;

    public HadoopController() {
        log.info("Hadoop请求已装载");
    }

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public Message list(String path, String status) {
        HdfsFileType type = StringUtils.isBlank(status) ? HdfsFileType.ALL:HdfsFileType.valueOf(status.toUpperCase());
        return toDataTable(manager.list(path, type));
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public Message upload(@RequestParam("file") MultipartFile file, String target) {
        try {
            manager.upload(target, file.getOriginalFilename(), false, file.getBytes());
            return Message.ok();
        }  catch (Exception e) {
            log.error("Hadoop上传文件{}至{}失败", file.getName(), target, e);
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/mkdirs", method = RequestMethod.POST)
    public Message mkdirs(@RequestBody HadoopDTO dto) {
        try {
            if (manager.mkdirs(dto.getPath())) {
                return Message.ok("新建目录成功");
            } else {
                return Message.ok("新建目录失败,刷新后再试");
            }
        } catch (Exception e) {
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/rename", method = RequestMethod.POST)
    public Message rename(@RequestBody HadoopDTO dto) {
        try {
            if (manager.rename(dto.getPath(), dto.getName())) {
                return Message.ok("重命名成功");
            } else {
                return Message.ok("重命名失败,刷新后再试");
            }
        } catch (Exception e) {
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/move", method = RequestMethod.POST)
    public Message move(@RequestBody HadoopDTO dto) {
        try {
            String[] ps = dto.getPath().split(",");
            if (manager.move(dto.getDest(), ps)) {
                return Message.ok("文件移动成功");
            } else {
                return Message.error("文件移动失败,刷新后再试");
            }
        } catch (Exception e) {
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/copy", method = RequestMethod.POST)
    public Message copy(@RequestBody HadoopDTO dto) {
        try {
            String[] ps = dto.getPath().split(",");
            if (manager.copy(dto.getDest(), ps)) {
                return Message.ok("文件粘贴成功");
            } else {
                return Message.error("文件粘贴失败,刷新后再试");
            }
        } catch (Exception e) {
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/toLocal", method = RequestMethod.POST)
    public Message toLocal(@RequestBody HadoopDTO dto) {
        File dir = new File(AppEnvironment.DATA_DIR.getValue(), dto.getDest());
        manager.copyToLocalDir(dir, dto.getPath().split(","));
        return Message.ok("拷贝成功,服务器上的存储目录：" + dir);
    }

    @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
    public Message delete(String path) {
        try {
            if (manager.delete(true, path.split(","))) {
                return Message.ok("文件删除成功");
            } else {
                return Message.ok("文件删除失败,刷新后再试");
            }
        } catch (Exception e) {
            return Message.error(e.getMessage());
        }
    }

    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public void download(String path, HttpServletResponse response) throws IOException {
        File dir = AppEnvironment.TEMP_DIR.getPath(DatePattern.localDateTime() + "_Hadoop").toFile();
        try {
            manager.copyToLocalDir(dir, path.split(","));
            ZipCompressHolder.builder().target(dir.toPath()).execute().download(response).delete();
        } catch (Exception e) {
            response.setStatus(Code.C500.getCode());
        } finally {
            CommonUtils.deleteDir(dir.toPath());
        }
    }

    @RequestMapping(value = "/pull", method = RequestMethod.GET)
    public ResponseEntity<Resource> download(String path) throws IOException {
        File dir = AppEnvironment.TEMP_DIR.getPath(DatePattern.localDateTime() + "_Hadoop").toFile();
        ResponseEntity<Resource> entity;
        Path target = null;
        try {
            manager.copyToLocalDir(dir, path.split(","));

            target = ZipCompressHolder.builder().target(dir.toPath()).execute().toPath();
            Resource resource = new ByteArrayResource(Files.readAllBytes(target));
            entity = ResponseEntity.ok()
                    .header("Access-Control-Expose-Headers", "Content-Filename")
                    .header("Content-Filename", URLEncoder.encode(target.getFileName().toString(), "UTF-8"))
                    .contentLength(Files.size(target))
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        } catch (FileNotFoundException e) {
            log.error("{} 文件不存在", target, e);
            entity = new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (Exception e) {
            log.error("{} 文件下载失败", path, e);
            entity = new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        } finally {
            CommonUtils.deleteDir(dir.toPath());
        }
        return entity;
    }
}
